package org.example.pims.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import org.example.admin.manage.service.SysAdminService;
import org.example.commons.config.MiniProgramInspectorsProperties;
import org.example.commons.config.MiniProgramUserProperties;
import org.example.commons.entity.SysAdmin;
import org.example.commons.entity.SysUser;
import org.example.commons.utils.RedisCache;
import org.example.commons.utils.WeiXinUtils;
import org.example.commons.vo.ResultVO;
import org.example.pims.menu.Menu;
import org.example.pims.security.LoginUser;
import org.example.pims.security.constant.Constants;
import org.example.pims.security.constant.RoleConstants;
import org.example.pims.security.service.AdminUserDetailsServiceImpl;
import org.example.pims.security.service.SysLoginService;
import org.example.pims.security.service.TokenService;
import org.example.pims.security.service.UserUserDetailsServiceImpl;
import org.example.pims.security.utils.ServletUtils;
import org.example.pims.security.utils.StringUtils;
import org.example.user.manage.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 登录验证
 */
@RestController
@RequestMapping("/api")
public class SysLoginController {
    @Autowired
    private SysAdminService adminService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SysLoginService loginService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private AdminUserDetailsServiceImpl adminUserDetailsService;

    @Autowired
    private UserUserDetailsServiceImpl userUserDetailsService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private MiniProgramUserProperties userProperties;

    @Autowired
    private MiniProgramInspectorsProperties inspectorsProperties;

    /**
     * 管理员 登录方法
     *
     * @param username 电话号
     * @param password 密码
     * @return 结果
     */
    @GetMapping("/login/admin")
    public ResultVO AdminLogin(@RequestParam(value = "username", required = false) String username,
                               @RequestParam(value = "password", required = false) String password,
                               @RequestParam(value = "code", required = false) String code) throws JsonProcessingException {
        if (StringUtils.isEmpty(username) && StringUtils.isEmpty(password)
                && StringUtils.isEmpty(code)) {
            return ResultVO.error("登录失败！！请检查填写信息");
        }
        //如果是微信一键登录
        if (StringUtils.isEmpty(username) && StringUtils.isEmpty(password)) {
            String openid = WeiXinUtils.getRealOpenid(code, inspectorsProperties.getAppId(),
                    inspectorsProperties.getAppSecret());
            //根据openid
            SysAdmin admin = adminService.findByOpenid(openid);
            if (admin == null) return ResultVO.error("登录失败！！你的账号尚未绑定该微信");
            username = admin.getPhone();
            password = admin.getPassword();
        }

        ResultVO ajax = ResultVO.success();
        // 生成令牌
        String token = loginService.login(username, password);
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }


    /**
     * 住户小程序端 登录方法
     *
     * @param username 电话号
     * @param password 密码
     * @return 结果
     */
    @GetMapping("/login/user")
    public ResultVO userLogin(@RequestParam(value = "username", required = false) String username,
                              @RequestParam(value = "password", required = false) String password,
                              @RequestParam(value = "code", required = false) String code) throws JsonProcessingException {
        if (StringUtils.isEmpty(username) && StringUtils.isEmpty(password)
                && StringUtils.isEmpty(code)) {
            return ResultVO.error("登录失败！！请检查填写信息");
        }
        //如果是微信一键登录
        if (StringUtils.isEmpty(username) && StringUtils.isEmpty(password)) {
            String openid = WeiXinUtils.getRealOpenid(code, userProperties.getAppId(),
                    userProperties.getAppSecret());
            //根据openid
            SysUser user = userService.findByOpenid(openid);
            if (user == null) return ResultVO.error("登录失败！！你尚未注册账号");
            username = user.getPhone();
            password = user.getPassword();
        }

        ResultVO ajax = ResultVO.success();
        // 生成令牌
        String token = loginService.userLogin(username, password);
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }

    @GetMapping("menu")
    public ResultVO getMenuList(){
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        List<? extends GrantedAuthority> grantedAuthorities = loginUser.getGrantedAuthorities();
        for (GrantedAuthority authority : grantedAuthorities) {
            if (RoleConstants.ROLE_SUPER_ADMIN.equals(authority.getAuthority()))
                return ResultVO.success(Menu.getMenuSuperAdmin());
            if (RoleConstants.ROLE_ADMIN.equals(authority.getAuthority()))
                return ResultVO.success(Menu.getMenuAdmin());
        }
        return ResultVO.success(Menu.getMenuCheckMan());
    }

    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping("getInfo")
    public ResultVO getInfo() {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        ResultVO resultVO = ResultVO.success(loginUser.getUser());
        List<String> roles = new ArrayList<>();
        for (GrantedAuthority authority : loginUser.getGrantedAuthorities()) {
            roles.add(authority.getAuthority());
        }
        resultVO.put("roles",roles);
        return resultVO;
    }

    /**
     * 更新登录管理员信息
     *
     * @return 用户信息
     */
    @PostMapping("/update/adminInfo")
    public ResultVO updateAdminInfo() {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        SysAdmin user = (SysAdmin) loginUser.getUser();
        user = adminService.queryById(user.getAdminId());
        LoginUser newLoginUser = (LoginUser) adminUserDetailsService.createLoginUser(user);
        loginUser.setGrantedAuthorities(newLoginUser.getGrantedAuthorities());
        loginUser.setPhone(newLoginUser.getUsername());
        loginUser.setUser(user);
        tokenService.setLoginUser(loginUser);
        return ResultVO.success(user);
    }

    /**
     * 更新登录用户信息
     *
     * @return 用户信息
     */
    @PostMapping("/update/userInfo")
    public ResultVO updateSysUserInfo() {
        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
        SysUser user = (SysUser) loginUser.getUser();
        user = userService.queryById(user.getUserId());
        LoginUser newLoginUser = (LoginUser) userUserDetailsService.createLoginUser(user);
        loginUser.setGrantedAuthorities(newLoginUser.getGrantedAuthorities());
        loginUser.setPhone(newLoginUser.getUsername());
        loginUser.setUser(user);
        tokenService.setLoginUser(loginUser);
        return ResultVO.success(user);
    }

    /**
     * 强制下线 管理员
     * @param id
     * @return
     */
    @Secured("ROLE_SUPER_ADMIN")
    @DeleteMapping("/delete/admin/{id}")
    public ResultVO deleteLoginUser(@PathVariable(name = "id") Long id){
        Set<String> keys = getLoginKey();

        for (String key : keys) {
            LoginUser user = redisCache.getCacheObject(key);
            try {
                SysAdmin admin = (SysAdmin) user.getUser();
                if (admin.getAdminId().equals(id)){
                    tokenService.delLoginUser(user.getToken());
                }
            }catch (ClassCastException ignored){
            }
        }
        return ResultVO.success();
    }

    /**
     * 批量强制下线 管理员
     * @param ids
     * @return
     */
    @Secured("ROLE_SUPER_ADMIN")
    @DeleteMapping("/delete/admin")
    public ResultVO deleteLoginUser(@PathVariable(name = "ids") Long[] ids){
        Set<String> keys = getLoginKey();

        for (String key : keys) {
            LoginUser user = redisCache.getCacheObject(key);
            try {
                SysAdmin admin = (SysAdmin) user.getUser();
                for (Long id : ids) {
                    if (admin.getAdminId().equals(id)){
                        tokenService.delLoginUser(user.getToken());
                    }
                }
            }catch (ClassCastException ignored){
            }
        }
        return ResultVO.success();
    }

    /**
     * 强制下线 住户
     * @param id
     * @return
     */
    @Secured({"ROLE_ADMIN","ROLE_SUPER_ADMIN"})
    @DeleteMapping("/delete/user/{id}")
    public ResultVO deleteLoginUser2(@PathVariable(name = "id") Long id){
        Set<String> keys = getLoginKey();

        for (String key : keys) {
            LoginUser user = redisCache.getCacheObject(key);
            try {
                SysUser sysUser = (SysUser) user.getUser();
                if (sysUser.getUserId().equals(id)){
                    tokenService.delLoginUser(user.getToken());
                }
            }catch (ClassCastException ignored){
            }
        }
        return ResultVO.success();
    }

    /**
     * 批量强制下线 住户
     * @param ids
     * @return
     */
    @Secured({"ROLE_ADMIN","ROLE_SUPER_ADMIN"})
    @DeleteMapping("/delete/user")
    public ResultVO deleteLoginUser2(@PathVariable(name = "ids") Long[] ids){
        Set<String> keys = getLoginKey();

        for (String key : keys) {
            LoginUser user = redisCache.getCacheObject(key);
            try {
                SysUser sysUser = (SysUser) user.getUser();
                for (Long id : ids) {
                    if (sysUser.getUserId().equals(id)){
                        tokenService.delLoginUser(user.getToken());
                    }
                }
            }catch (ClassCastException ignored){
            }
        }
        return ResultVO.success();
    }

    private Set<String> getLoginKey(){
        return redisTemplate.keys(Constants.LOGIN_TOKEN_KEY + "*");
    }

}
